package com.yx.websocketim

import android.app.Notification
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.Service
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.graphics.Color
import android.os.*
import android.util.Log
import okhttp3.*
import okhttp3.internal.ws.RealWebSocket
import okio.ByteString
import java.util.concurrent.TimeUnit

/**
 * Creator:Yx
 * Time:2022/7/11 17:34
 * Description: WebSocket连接服务,继承Service()
 */
class MsgService : Service() {

    /**
     * 调⽤ bindService 启动服务， Service ⽣命周期⽅法为： onCreate()->onBind() 多次调⽤  bindService 并不会多次调⽤ onBind(),
     * 当 Activity 退出时，该 Service 销毁，调⽤： onUnbind()->onDestroy();
     */
    override fun onBind(intent: Intent?): IBinder? {
        TODO("Not yet implemented")
    }

    // 声明成lateinit的变量，如果在整个代码里面都没有进行任何的初始化，那么能否编译通过？如果你加上了lateinit关键字，
    // kotlin的编译器不会做这种检查。如果你将变量声明为lateinit，它就认为你肯定会初始化，至于你是怎么初始化它的，它就不管了
    private lateinit var okHttpClient: OkHttpClient
    private var webSocket: RealWebSocket? = null


    companion object {
        //  const只能修饰val，不能修饰var类型变量。当你在伴生对象中定义了val则系统会提示你要用const来修饰
        /**
         * （1）const val 修饰的属性相当于java中的public final static修饰的常量，可以通过类名直接访问。
         * （2）val 修饰的属性相当于java中private final static修饰的常量，由于可见行为private，所以只能通过生成getter方法访问。
         * （3）出于性能考虑，使用const val方式可以避免频繁函数调用。
         */
        const val NOTIFICATION_ID = 1234 // 保活ID
    }


    /**
     * 系统方法
     */
    override fun onCreate() {  // 仅初始化执行一次
        super.onCreate()
        LogUtils.iYx("onCreate")
        // 开启保活 用于需要特定条件才执行后台任务的场景：重启、开关网络，插入充电器
        // Intent ret = new Intent(this,  Service.class);
        // startService(ret);
    }

    // 实现 变量 指向类
    val mHandlers: Handler = Handler(Looper.getMainLooper()) {
        when (it.what) {
            0 -> {
            }
            1 -> {
            }
            2 -> {
            }
        }
        false
    }
    val mHandler: Handler = object : Handler(Looper.getMainLooper()) {
        override fun handleMessage(msg: Message) {
            super.handleMessage(msg)
            when (msg.what) {
                0 -> {
                }
                1 -> {
                }
                2 -> {
                }
            }
        }
    }

    /**
     * 系统方法
     */
    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        LogUtils.iYx("onStartCommand")
        if (webSocket != null) {
            // 因为Intent有问号，所以需要非空判断, ?:与?.连这用，为空则返回"ws://localhost:9000"
            val tests: String = intent?.getStringExtra("Texts") ?: ""
            LogUtils.iYx("发送新消息：$tests")
            if (tests.isNotEmpty())
            // webSocket.let { it!!.send(tests) } // let 当调用者不为空时执行里面内容，!!表示这个变量为空就抛出异常
                webSocket?.send(tests) // ？表示这个参数为空就不执行后面.send
        } else {
            // 因为Intent有问号，所以需要非空判断, ?:与?.连这用，为空则返回.
            // 地址："ws://121.40.165.18:8800" 每天限额50次，地址："ws://82.157.123.54:9010/ajaxchattest"无限制
            // 地址："ws://149.57.130.231:9502" 长期
            val wsUrl = "ws://149.57.130.231:9502"
            val url: String =
                intent?.getStringExtra("Urls") ?: wsUrl
            LogUtils.iYx(url)
            okHttpClient = OkHttpClient.Builder()
                .connectTimeout(20, TimeUnit.SECONDS)     // 设置连接超时 20s
                .readTimeout(10, TimeUnit.SECONDS)      // 设置SocketTimeout读取超时 10s
                .build()
            // 普通不带任何数据请求
            var request: Request = Request.Builder().url(url).build()
            // 带请求数据Get请求
            val headersBuilder: Headers.Builder = Headers.Builder()
            if (wsUrl.contains("ajax")) {
                // 主要请求头参数
                headersBuilder.add("Host", "82.157.123.54:9010")
                headersBuilder.add("Origin", "http://coolaf.com")
                // 可有可无参数
                headersBuilder.add("Accept-Encoding", "gzip, deflate")
                headersBuilder.add("Accept-Language", "zh-CN,zh;q=0.9,en;q=0.8,ja;q=0.7")
                headersBuilder.add("Cache-Control", "no-cache")
                headersBuilder.add("Connection", "Upgrade")
                headersBuilder.add("Pragma", "no-cache")
                headersBuilder.add(
                    "User-Agent",
                    "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36"
                )
                headersBuilder.add("Sec-WebSocket-Key", "a9zOFbL43kE9eXaCp4HpJw==")
                headersBuilder.add(
                    "Sec-WebSocket-Extensions",
                    "permessage-deflate; client_max_window_bits"
                )
                headersBuilder.add("Sec-WebSocket-Version", "13")
                headersBuilder.add("Upgrade", "websocket")
                val headers = headersBuilder.build()
                request = Request.Builder().url(url).get().headers(headers).build()
            }

            //  变量指向实现方法返回抽象类
            val listener: WebSocketListener = inItWebSocketListener()

            // as关键字可以用于对象的类型转换
            webSocket = okHttpClient.newWebSocket(request, listener) as RealWebSocket
            startNotifi(3)
        }
        return super.onStartCommand(intent, flags, startId)
    }


    /**
     * 实现方法返回抽象类
     * WebSocket消息监听
     */
    private fun inItWebSocketListener(): WebSocketListener {
        // val listener:WebSocketListener = object : WebSocketListener(){}
        return object : WebSocketListener() {
            override fun onOpen(webSocket: WebSocket, response: Response) {
                super.onOpen(webSocket, response)
                LogUtils.iYx("WebSocket - OnOpen")
                webSocket.send("我来了~")
            }

            override fun onMessage(webSocket: WebSocket, text: String) {
                super.onMessage(webSocket, text)
                LogUtils.iYx("服务器Message-->text:$text")
                // 发送广播，发送WebSocket得到的消息到主页列表
                sendBroadcastMsg(text)
            }

            override fun onMessage(webSocket: WebSocket, bytes: ByteString) {
                super.onMessage(webSocket, bytes)
                LogUtils.iYx("onMessage-->bytes:$bytes")
            }

            override fun onClosed(webSocket: WebSocket, code: Int, reason: String) {
                super.onClosed(webSocket, code, reason)
                LogUtils.iYx("onClosed-->code:$code\treason$reason")
                // webSocketUtils.endHeart() // 停止心跳
                mHandler.sendEmptyMessage(0) // 停止心跳
            }

            override fun onClosing(webSocket: WebSocket, code: Int, reason: String) {
                super.onClosing(webSocket, code, reason)
                LogUtils.iYx("onClosing-->code:$code\treason$reason")
                // webSocketUtils.endHeart() // 停止心跳
                mHandler.sendEmptyMessage(0) // 停止心跳
            }

            override fun onFailure(webSocket: WebSocket, t: Throwable, response: Response?) {
                super.onFailure(webSocket, t, response)
                LogUtils.iYx("onFailure-->throwable:$t")
                // webSocketUtils.reConnect()
                // webSocketUtils.endHeart() // 停止心跳
                mHandler.sendEmptyMessage(0) // 停止心跳
            }
        }
    }

    /**
     * WebSocket 重连
     * 替换了url
     */
    fun reConnect(url: String) { // 替换了url
        var urls = url // 这里可以看见缺点很明显，函数参数默认是val类型不能被重新赋值，所以多声明了一个变量
        if (urls.isEmpty()) urls = "ws://121.40.165.18:8800"
        webSocket?.cancel()
        val request: Request = Request.Builder().url(urls).build()
        //  变量指向实现方法返回抽象类
        val listener: WebSocketListener = inItWebSocketListener()
        webSocket = okHttpClient.newWebSocket(request, listener) as RealWebSocket
    }

    /**
     * WebSocket 断开
     */
    fun cancel() {
        webSocket?.cancel()
    }

    /**
     * 开启通知栏
     *
     * @param t
     */
    private fun startNotifi(t: Int) {
        // ---通知栏提醒 start --白色保活--
        Log.i("aaaa", "----启动通知栏----")
        val manager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
        // 实例化Notification.Builde并设置相关属性,兼容低版本
        var builder = Notification.Builder(this)
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            builder = Notification.Builder(this, "666999")
        }
        builder.setContentTitle("WebSocket.IM..") // 设置通知标题
        builder.setContentText("您有新的消息请注意查收!") // 设置通知内容
        builder.setContentInfo("每隔" + t + "分钟") // 额外的内容，显示在右下角，10以上没用。
        builder.setSmallIcon(R.mipmap.ic_launcher) // 设置通知的图标
        builder.setAutoCancel(true) // 设置点击通知打开应用后，该通知自动消失
        builder.setWhen(System.currentTimeMillis()) // 设置通知被创建的时间，默认为系统发出通知的时间，通常不用设置
        builder.setShowWhen(true)
        builder.setVibrate(null) // 设置震动，无
        builder.setSound(null) // 设置提示音，无
        // builder.setLights(0, 0, 0); // 设置支持三色灯提醒,这个方法就是设置不同场景下的不同颜色的灯
        builder.setOngoing(true) // 不能被用户x掉会一直显示，如音乐播放等
        // builder.setProgress(); // 设置通知重要程度
        // builder.setColor(); // 设置通知栏颜色
        builder.setNumber(3) // 这里用来显示右下角的数字
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            val channel =
                NotificationChannel("666999", "安卓10", NotificationManager.IMPORTANCE_DEFAULT)
            channel.enableLights(false) // 是否在桌面ICON上显示小红点
            channel.lightColor = Color.RED // 小红点颜色
            channel.setShowBadge(false) // 是否在久按桌面图标时显示此渠道的通知
            manager.createNotificationChannel(channel)
        }
        // 打开通知方式一：
        // 通过builder.build()方法生成Notification对象,并发送通知,id=1
        // manager.notify(RunService.NOTIFICATION_ID, builder.build());
        // 打开通知方式二,安卓10.0：
        startForeground(NOTIFICATION_ID, builder.build())

        /*
        // --------通知栏提醒2--------
        // 启动服务去同时绑定该前台通知栏，当RunService还是在前台运行
        Intent innerIntent = new Intent(ProxyApplication.getInstance(), CancelNoticeService.class);
        innerIntent.putExtra("T", t);
        startService(innerIntent);
        //---通知栏end
        */
    }

    /**
     * 取消通知
     */
    private fun deleteNotifi() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
            val mManager =
                this.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
            mManager.cancel(NOTIFICATION_ID)
            // mManager.cancelAll()
        }
    }

    /**
     * 发送广播，发送WebSocket得到的消息到主页列表
     */
    private fun sendBroadcastMsg(text: String) {
        // 发送广播,理论上谁要发送广播，则谁来创建广播。这里我们放在了Application中来做
        YxApplication.intent.putExtra("message", text)
        sendBroadcast(YxApplication.intent)
    }


    class MsgBinder : Binder() {

        fun setData(intent: Intent?) {
        }

        /**
         * 获取当前Service的实例
         *
         * @return
         */
        fun getService(): MsgService {
            return MsgService()
        }

    }

    override fun onDestroy() {
        super.onDestroy()
        cancel()
    }


}